package com.lzj.gen.jetbrains;

import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStrictStyle;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;

import java.io.IOException;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;

/**
 * Created by lzj on 2023/11/24
 */
public class CertUtil {

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public static void genCert(String certPath, String keyPath)
            throws NoSuchAlgorithmException, CertificateException, IOException,
            OperatorCreationException {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        keyPairGen.initialize(4096);
        KeyPair keyPair = keyPairGen.generateKeyPair();

        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

        //根证书Issue基本信息
        X500Name requestName = getX500Name("Jinbaozi");
        X500Name issuerName = getX500Name("JetProfile CA");
        // 证书序列号
        BigInteger serial = BigInteger.valueOf(System.currentTimeMillis() / 1000);
        //证书有 起始日期 与 结束日期
        LocalDateTime now = LocalDateTime.now();
        Date notBefore = Date.from(now.minusYears(1).atZone(ZoneId.systemDefault()).toInstant());
        Date notAfter = Date.from(now.plusYears(10).atZone(ZoneId.systemDefault()).toInstant());
        //构建证书的build
        X509Certificate certificate = createCert(issuerName, requestName, serial, notBefore, notAfter, publicKey,
                privateKey);
        PemUtil.saveToPemFile(certPath, "CERTIFICATE", certificate.getEncoded());
        PemUtil.saveToPemFile(keyPath, "PRIVATE KEY", privateKey.getEncoded());
    }

    private static X500Name getX500Name(String cn) {
        X500NameBuilder rootIssueMessage = new X500NameBuilder(
                BCStrictStyle.INSTANCE);
        rootIssueMessage.addRDN(BCStyle.CN, cn);
//        rootIssueMessage.addRDN(BCStyle.O, O);
//        rootIssueMessage.addRDN(BCStyle.L, L);
//        rootIssueMessage.addRDN(BCStyle.ST, ST);
//        rootIssueMessage.addRDN(BCStyle.C, C);
//        rootIssueMessage.addRDN(BCStyle.OU, OU);
        return rootIssueMessage.build();
    }

    private static X509Certificate createCert(X500Name issuerName, X500Name reqName, BigInteger serial, Date notBefore,
            Date notAfter, PublicKey userPublicKey, RSAPrivateKey privateKey)
            throws OperatorCreationException, CertificateException {
        X509v3CertificateBuilder x509v3CertificateBuilder = new JcaX509v3CertificateBuilder(
                issuerName, serial, notBefore, notAfter, reqName, userPublicKey);
        //签名
        ContentSigner signer = new JcaContentSignerBuilder("SHA256WITHRSA").setProvider("BC").build(privateKey);

        X509CertificateHolder x509CertificateHolder = x509v3CertificateBuilder.build(signer);
        JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter();
        certificateConverter.setProvider("BC");
        return certificateConverter.getCertificate(x509CertificateHolder);
    }
}
